package pacman;
import java.io.IOException;
import java.util.Map;

import lejos.nxt.LightSensor;
import lejos.nxt.SensorPort;
import lejos.nxt.UltrasonicSensor;
import maze.Location;
import maze.Maze;
import sensors.realSensors.RealInfraredSensor;
import sensors.realSensors.RealLightSensor;
import sensors.realSensors.RealUltrasonicSensor;
import simulation.ColorMap;
import simulation.GuiTest;
import simulation.Simulator;
import Analyser.BarcodeAnalyser;

import behaviour.Explorer;
import behaviour.Explorer02;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Command;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.ConsumerCancelledException;
import com.rabbitmq.client.FlowListener;
import com.rabbitmq.client.GetResponse;
import com.rabbitmq.client.Method;
import com.rabbitmq.client.ReturnListener;
import com.rabbitmq.client.ShutdownListener;
import com.rabbitmq.client.ShutdownSignalException;
import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.AMQP.Basic.RecoverOk;
import com.rabbitmq.client.AMQP.Channel.FlowOk;
import com.rabbitmq.client.AMQP.Confirm.SelectOk;
import com.rabbitmq.client.AMQP.Exchange.BindOk;
import com.rabbitmq.client.AMQP.Exchange.DeclareOk;
import com.rabbitmq.client.AMQP.Exchange.DeleteOk;
import com.rabbitmq.client.AMQP.Exchange.UnbindOk;
import com.rabbitmq.client.AMQP.Queue.PurgeOk;
import com.rabbitmq.client.AMQP.Tx.CommitOk;
import com.rabbitmq.client.AMQP.Tx.RollbackOk;

import communication.Communicator;
import communication.Config;
import communication.IRSeekerV2;

public class Main {
	
	
	public static void main (String [] args) throws IOException, ShutdownSignalException, ConsumerCancelledException, InterruptedException{
		
		//testMaze();
		//testGui();
		//testCommunicator(); FAILS
		
		//testColorMap();
		//testBarcodeAnalyser();
//		testRidingBarcodeAnalyser();
		
//		testExplorer();
		testRealRobotMazeExplorer();
		
		//testRabbit();
		
		//testGhost();
		
	}
	
	private static void testRealRobotMazeExplorer() throws IOException {
		/*
		4x6

		?????_ _
		????| | |
		?_?_|   |
		|  _ _| |
		|    _| |
		| | |????
		|_ _|????
		 */
		
		char[][] walls = {
				{0,0,0,0,0,1,0,1,0},
				{0,0,0,0,1,2,1,2,1},
				{0,1,0,1,1,2,2,2,1},
				{1,2,2,1,2,1,1,2,1},
				{1,2,2,2,2,1,1,1,1},
				{1,2,1,2,1,0,0,0,0},
				{1,1,2,1,1,0,0,0,0}};
		
		Maze maze = new Maze(walls);
		ColorMap colorMap = new ColorMap();
		colorMap.setupMap(maze, maze.getSize(), maze.getSize());
		Simulator simulator = new Simulator(maze, colorMap);
		
		Pacman pacman = new Pacman();
		pacman.setLocation(new Location(60, 60));
		Ghost ghost = new Ghost(new Location(20, 20), 90, "Jos");
		Explorer explorer = new Explorer(ghost.getMaze());
		ghost.strategy = explorer;
		
		ghost.setInfraredSensor(new RealInfraredSensor(ghost));
		ghost.setLightSensor(new RealLightSensor(ghost));
		ghost.setUltrasonicSensor(new RealUltrasonicSensor(ghost));
		
		Communicator communicator = new Communicator();		
		ghost.setCommunicator(communicator);
		
		simulator.addGhost(ghost, new Location(20, 20), 90);
		simulator.setPacman(pacman);
		
		GuiTest Gui = new GuiTest(simulator);
		
		ghost.run();
	}

	private static void testGui() throws IOException
	{
		char[][] walls = { //index with maze[-y][x]
				{2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2}, 
				{1,1,2,1,2,1,2,2,2,2,1,2,1,2,2,1,2,1,2,1,2,1,2,1,2,2,1,2,2,1,2,1,2,1,2,2,1,2,2,2,1},
				{1,2,2,1,2,1,2,1,1,1,2,1,2,2,1,1,2,1,2,1,2,1,2,2,2,1,1,2,1,1,2,2,1,2,2,2,1,2,1,2,1},
				{1,2,1,2,1,1,2,2,2,1,2,1,2,2,2,1,2,2,2,1,2,2,1,1,2,1,2,1,2,1,2,1,1,2,1,1,1,2,1,2,1},
				{1,2,1,1,2,1,2,1,2,1,2,2,1,2,2,1,1,2,1,2,1,1,2,1,2,1,2,1,2,1,2,2,1,1,2,1,2,1,1,2,1},
				{1,2,1,2,2,1,2,1,2,1,2,1,1,1,2,1,1,2,1,2,2,1,2,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,2,1,1},
				{1,2,1,2,2,2,1,2,2,1,2,1,2,1,2,1,2,1,2,1,2,2,1,2,2,1,2,1,2,1,2,1,2,2,1,1,2,1,2,2,1},
				{1,2,1,2,1,2,1,2,1,2,2,1,2,1,2,1,2,1,2,2,1,2,1,2,1,2,2,1,2,1,2,2,1,2,2,1,2,1,2,1,1},
				{1,2,1,2,1,1,1,2,1,2,1,1,2,1,2,1,2,2,1,2,1,2,1,2,1,2,1,2,1,2,2,2,1,2,1,2,2,2,2,2,1},
				{1,2,1,2,2,2,1,2,1,1,2,1,2,1,2,1,2,1,1,2,1,2,1,2,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,2,1},
				{1,2,1,2,1,2,1,2,2,1,2,1,2,1,2,1,2,1,2,1,1,2,1,2,1,2,1,2,1,1,2,1,2,2,1,2,1,2,1,2,1},
				{1,1,2,1,1,1,2,1,1,2,2,1,2,1,2,1,2,1,2,1,2,1,1,2,1,2,2,1,1,1,2,2,1,2,1,2,1,2,1,2,1},
				{1,2,1,2,2,1,2,2,1,2,2,1,2,1,2,1,2,1,2,2,2,1,1,2,1,1,2,1,2,2,2,1,1,2,1,2,1,2,1,2,1},
				{1,1,2,1,1,2,2,1,1,2,2,1,2,1,2,1,2,1,2,1,1,1,2,2,2,1,2,2,1,2,1,2,1,2,1,1,2,1,1,2,1},
				{1,2,2,1,2,2,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,1,2,1,2,1,2,1,1,2,1,2,2,2,1,1},
				{1,2,2,2,1,2,1,1,2,1,2,2,1,2,2,1,2,1,2,2,2,1,2,1,2,1,2,1,1,2,1,2,2,1,2,1,2,1,1,2,1},
				{1,1,1,2,1,1,2,1,2,2,1,2,1,2,1,2,2,1,2,2,1,1,2,1,2,2,2,1,1,2,1,2,1,1,2,1,2,1,2,2,1},
				{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
				{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
				{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
				{1,1,2,1,2,1,2,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,2,1,2,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,1}};
		
		Maze maze = new Maze(walls);
		ColorMap colorMap = new ColorMap();
		colorMap.setupMap(maze, 20, 20);
		Simulator simulator = new Simulator(maze, colorMap);
		
		Pacman pacman = new Pacman();
		Ghost ghost1 = new Ghost(new Location(60,20), 0, "Jos");
		Ghost ghost2 = new Ghost(new Location(400,400), 0,"Jef");
		Ghost ghost3 = new Ghost(new Location(400,200), 0,"Jan");
		Ghost ghost4 = new Ghost(new Location(200,400), 0,"Joe");
				
		simulator.setPacman(pacman);
		simulator.addGhost(ghost1, ghost1.getLocation(), ghost1.getRotation());
		simulator.addGhost(ghost2, ghost1.getLocation(), ghost1.getRotation());
		simulator.addGhost(ghost3, ghost1.getLocation(), ghost1.getRotation());
		simulator.addGhost(ghost4, ghost1.getLocation(), ghost1.getRotation());
		
		//GuiTest gui = new GuiTest(simulator, maze, colorMap);
	}

	private static void testCommunicator()
	{
		Communicator comm = new Communicator();
		comm.travel(20);
		System.out.println(comm.getDistance());
	}
	
	private static void testGhost() throws IOException{
		ColorMap colorMap = new ColorMap();
		Maze maze= new Maze(100);
		Simulator simulator = new Simulator(maze, colorMap);
		Ghost ghost = new Ghost(new Location(0,0), 0, "Jan");
		simulator.addGhost(ghost, new Location(0,0), 0);
		ghost.run();
	}
	
	private static void testMaze()
	{
		/**
		 * Test Maze:
		 * 
		 *  _ _ _
		 * |  _  |
		 * | |_| |
		 * |_ _ _|
		 * 
		 * 2121212
		 * 1221221
		 * 1211121
		 * 1121211
		 * 
		 */
		/**char mazedata[4][7] = {
				{2,1,2,1,2,1,2},
				{1,2,2,1,2,2,1},
				{1,2,1,1,1,2,1},
				{1,1,2,1,2,1,1}
		}
		Maze maze = new Maze(mazedata);	
		
		Ghost ghost = new Ghost(new Location(0.0,0.0), maze);
		
		System.out.println("Start locatie");
		System.out.println(ghost.getLocation());
		System.out.println("Start rotatie");
		System.out.println(ghost.getRotation());
		System.out.println("Ultrasonic:");
		System.out.println(ghost.getUltrasonicSensor().getDistance());
		
		
		Simulator simulator = new Simulator();
		Pacman pacman = new Pacman(new Location(40,0), simulator);
		simulator.addGhost(ghost);
		simulator.setPacman(pacman);
		System.out.println("InfraRed:");
		System.out.println(ghost.getInfraredSensor().getDirection());
		
		ghost.rotate(90);
		System.out.println("InfraRed:");
		System.out.println(ghost.getInfraredSensor().getDirection());
		
		ghost.rotate(-45);
		System.out.println("InfraRed:");
		System.out.println(ghost.getInfraredSensor().getDirection());
		
		ghost.rotate(135);
		System.out.println("InfraRed:");
		System.out.println(ghost.getInfraredSensor().getDirection()); **/
	}
	
	private static void testColorMap()
	{
		ColorMap colorMap = new ColorMap();
		
		//colorMap.testReadImage();
		//colorMap.testAddBarcode();
		//colorMap.setupMap();
		//colorMap.testGetSensorReading();
		colorMap.TestReadValueOverlap();
		
	}
	
	private static void testBarcodeAnalyser()
	{
		BarcodeAnalyser analyser = new BarcodeAnalyser();
		
		//analyser.TestGetLastPossibleReading();
		//analyser.TestCalculateBarcode();
		analyser.TestUpdate();
	}
	
	private static void testRidingBarcodeAnalyser() throws IOException
	{
		/**
		 * Test Maze:
		 * 
		 *  _ _ _
		 * |  _  |
		 * |b|_| |
		 * |_ _ _|
		 * 
		 * 2121212
		 * 1221221
		 * 1211121
		 * 1121211
		 * (b = barcode 01011010, -y to y)
		 */
		char mazedata[][] = {
				{2,1,2,1,2,1,2},
				{1,2,2,1,2,2,1},
				{1,2,1,1,1,2,1},
				{1,1,2,1,2,1,1}
		};
		
		Maze maze = new Maze(mazedata);
		ColorMap colormap = new ColorMap();
		colormap.setupMap(maze, 3, 3);
		colormap.AddBarcode(0, 1, "01101010", 1);
		colormap.AddBarcode(0, 0, "01101010", 1);
		
		//colormap.showImage(colormap.tileMap[0][0]);
		colormap.showImage(colormap.tileMap[0][1]);
		//colormap.showImage(colormap.tileMap[0][2]);
		
		Ghost ghost = new Ghost(new Location(20,1), 90, "jos");
		ghost.barcodeAnalyser.SetBrownValue(128);
		
		Simulator simulator = new Simulator(maze, colormap);
		simulator.addGhost(ghost, new Location(20,1), 90);
		//simulator.setPacman(new Pacman(simulator));
		
				
		//simulator.getGhostLocations().put(ghost, new Location(20, 14.6));		
		//System.out.println(ghost.getLightSensor().readValue());
		
		System.out.println("Started");
		ghost.run();
		ghost.travel(99);
				
		
		
		int prevReading = 0;
		Location ghostLoc = simulator.getGhostLocations().get(ghost);
		
		while(ghostLoc.y<=85)
		{
			ghostLoc = simulator.getGhostLocations().get(ghost);
			System.out.println(ghostLoc.y);
			
			
			int cReading = ghost.getLightSensor().readValue();
			if(prevReading != cReading)
			{
				prevReading = cReading;
				//System.out.println(cReading+ " Pos: "+ghostLoc.x+" "+ghostLoc.y);
			}
			
		}
		System.out.println("Finished Run");
		ghost.terminated = true;
		System.out.println("Expected barcode: 01010110 (2 times)");
		
		/*
		String output = "";
		for(int i=0; i<ghost.barcodeAnalyser.readings.size(); i++)
		{
			output+=ghost.barcodeAnalyser.readings.get(i);
			output+=" ";			
		}
		System.out.println(output);*/
		
		
		
	}
	
	private static void sleep(int milli)
	{
		try {
			Thread.sleep(milli);
		} catch (InterruptedException e) {
		}
	}

	private static void testBarcodeReal() throws IOException
	{
		Ghost ghost = new Ghost(new Location(0,0), 0, "Jef");
		ghost.setInfraredSensor(new RealInfraredSensor(ghost));
		ghost.setLightSensor(new RealLightSensor(ghost));
		ghost.setUltrasonicSensor(new RealUltrasonicSensor(ghost));
		ghost.setCommunicator(new Communicator());
		
		char mazedata[][] = {
				{2,1,2,1,2,1,2},
				{1,2,2,1,2,2,1},
				{1,2,1,1,1,2,1},
				{1,1,2,1,2,1,1}
		};
		Maze maze = new Maze(mazedata);	
		ColorMap colormap = new ColorMap();
		colormap.setupMap(maze, 3, 3);
		Simulator sim = new Simulator(maze, colormap);
		ghost.setSimulator(sim);
		
		ghost.run();
		
		ghost.travel(40);
		//Wanneer de robot over een gekende en herkende barcode rijdt, output hij deze barcode
		//(ge moet de barcode dus wel nog toevoegen in de barcodeanalyser)
		
		while(true)
		{
			System.out.println(ghost.getLightSensor().readValue());
		}
	}

	private static void testExplorer() throws IOException, ShutdownSignalException, ConsumerCancelledException, InterruptedException
	{
		char[][] walls = { //index with maze[-y][x]
				{2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2}, 
				{1,1,2,1,2,1,2,2,2,2,1,2,1,2,2,1,2,1,2,1,2,1,1},
				{1,2,2,1,2,1,2,1,1,1,2,1,2,2,1,1,2,1,2,1,2,1,1},
				{1,2,1,2,1,1,2,2,2,1,2,1,2,2,2,1,2,2,2,1,2,2,1},
				{1,2,1,1,2,1,2,1,2,1,2,2,1,2,2,1,1,2,1,2,1,1,1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}};
		

		
		Maze maze = new Maze(walls);
		ColorMap colorMap = new ColorMap();
		colorMap.setupMap(maze, maze.getSize(),maze.getSize());
		Simulator simulator = new Simulator(maze, colorMap);
		Pacman pacman = new Pacman();
		pacman.setLocation(new Location(140,140));
		simulator.setPacman(pacman);
		colorMap.AddBarcode(1, 3, "01010110", 0);
		colorMap.AddBarcode(5, 2, "01110110", 0);
		colorMap.AddBarcode(0, 2, "01011100", 1);
		
		simulator.getMaze().addBarcode(1, 3, "01010110", 0);
		simulator.getMaze().addBarcode(5, 2, "01110110", 0);
		simulator.getMaze().addBarcode(0, 2, "01011100", 1);
		
	    Game game = new Game();
		Ghost ghost = new Ghost(new Location(20,20), 0, "Jos");
		Ghost ghost1 = new Ghost(new Location(20,20), 0, "Jef");
		Ghost ghost2 = new Ghost(new Location(20,20), 0, "Jan");
		Ghost ghost3 = new Ghost(new Location(20,20), 0, "Jeroen");
		
		ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(Config.HOST_NAME);
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(Config.EXCHANGE_NAME, "fanout");
        
		ghost.strategy = new Explorer(ghost.getMaze());
		ghost1.strategy = new Explorer(ghost1.getMaze());
		ghost2.strategy = new Explorer(ghost2.getMaze());
		ghost3.strategy = new Explorer(ghost3.getMaze());
		//Explorer02 explorer = new Explorer02(ghost.getMaze());
		//explorer.sim = simulator;
		//explorer.g = ghost;
		//ghost.strategy = explorer;
		
		simulator.addGhost(ghost, new Location(140, 140), 0);
		simulator.addGhost(ghost1, new Location(60, 60), 0);
		simulator.addGhost(ghost2, new Location(100, 60), 0);
		simulator.addGhost(ghost3, new Location(20, 140), 0);
		simulator.speed = 1000;
		simulator.getMaze().draw(-1, -1);
		GuiTest Gui = new GuiTest(simulator);
		
		Thread t1 = new Thread(new GhostRunner(ghost));
		Thread t2 = new Thread(new GhostRunner(ghost1));
		Thread t3= new Thread(new GhostRunner(ghost2));
		Thread t4 = new Thread(new GhostRunner(ghost3));
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}
